package com.craftsman.tomcat.nio;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import java.io.FileInputStream;
import java.net.ServerSocket;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;


/**
 * 用以改造既有传统socket方式tomcat servlet 容器
 * @author chenfanglin
 * @date 2021年05月16日
 */
public class BXNIOTomcat {

    private int port=8081;

    private Map<String,BXNIOServlet> SERVLET_MAP =new HashMap<String,BXNIOServlet>();

    private Properties WEB_XML =new Properties();

    private void init(){
        String webInf=this.getClass().getResource("/").getPath();

        try {
            FileInputStream fis=new FileInputStream(webInf+"web-nio.properties");
            WEB_XML.load(fis);
            for(Object k: WEB_XML.keySet()){
                String key=k.toString();
                if(key.endsWith(".url")){
                    String servletName=key.replaceAll("\\.url$","");
                    String url= WEB_XML.getProperty(key);
                    String className= WEB_XML.getProperty(servletName+".className");
                    BXNIOServlet obj=(BXNIOServlet) Class.forName(className).newInstance();
                    SERVLET_MAP.put(url,obj);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void start(){

        //1.初始化servlet
        init();
        EventLoopGroup bossGroup=new NioEventLoopGroup();
        EventLoopGroup workerGroup=new NioEventLoopGroup();
        try {
            //2.启动nio对象bootstrap
            ServerBootstrap serverBootstrap=new ServerBootstrap();
            serverBootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new HttpResponseEncoder());
                            ch.pipeline().addLast(new HttpRequestDecoder());
                            ch.pipeline().addLast(new BXTomcatHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE,true);
            ChannelFuture f=serverBootstrap.bind(this.port).sync();
            System.out.println("bx nio tomcat 已经启动 监听的端口:"+this.port);
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }


    public  class BXTomcatHandler extends ChannelInboundHandlerAdapter {

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            if(msg instanceof HttpRequest){
                System.out.println("接收到前端请求msg"+msg);
                HttpRequest request=(HttpRequest) msg;
                BXNIORequest realRequest=new BXNIORequest(ctx,request);
                BXNIOResponse realResponse=new BXNIOResponse(ctx,request);
                String url=realRequest.getRequest().uri();
                if(SERVLET_MAP.containsKey(url)){
                    SERVLET_MAP.get(url).service(realRequest,realResponse);
                }else{
                    realResponse.write("nio tomcat not found request url");
                }
            }
        }
    }
    public static void main(String[] args) {
        new BXNIOTomcat().start();
        System.out.println("this bx nio tomcat already started");
    }

}
